import numpy as np
from aStar import aStar
from utils import crd_2_3, crd_game_to_gird, crd_grid_to_game, one_zero_map, parse_map
MOVE={
  (0,0):'STOP',
  (0, 1):'RIGHT',
  (0, -1):'LEFT',
  (1, 0):'DOWN',
  (-1, 0):'TOP'
}
def calcAnimal(stat):
  animals=[]
  animalsMap={}
  for an in stat['animalStateVos']:
    animal=an.copy()
    animal['x'],animal['y']=animal['y'],animal['x']
    animals.append(animal)
    animalsMap[animal['animalId']]=animal

  player=[p.copy() for p in stat['playerStateVos'] if p['playerId']==stat['playerId']][0]
  player['x'],player['y']=player['y'],player['x']
  speed10=player['speed']==10
  order=[0,1,3,2,4]
  map=parse_map(stat)
  pass_map=one_zero_map(map)
  
  
  one_map=np.zeros(map.shape).tolist()
  dir={
    1:(-1,0),
    2:(1,0),
    3:(0,-1),
    4:(0,1)
  }
  
  for animal in animals:
    x,y=crd_game_to_gird((animal['x'],animal['y']))
    if one_map[x][y]==0:
      one_map[x][y]=[]
    one_map[x][y].append(animal['animalId'])
    while True:
      dx,dy=dir[animal['movingDirect']]
      x,y=dx+x,dy+y
      if x>=0 and x<map.shape[0] and y >=0 and y<map.shape[1] and pass_map[x][y]==1:
        if one_map[x][y]==0:
          one_map[x][y]=[]
        one_map[x][y].append(animal['animalId'])
      else:
        break
  
  # 玩家所在行或列3格内是否有动物，这种最好抓优先抓这种。
  x,y=crd_game_to_gird((player['x'],player['y']))
  
  re_animal_1=None
  re_end_1=None
  re_routes_1=None
  if one_map[x][y]!=0:
    target=None
    distance=0
    for id in one_map[x][y]:
      animal=animalsMap[id]
      x1,y1=crd_game_to_gird((animal['x'],animal['y']))
      distance_=abs(y1-y)+abs(x1-x)
      if (not target or distance_<distance) and distance_<=3:
        target=animal
        distance=distance_
    if target:    
      move=dir[target['movingDirect']]
      dx,dy=-1*move[0],-1*move[1]
     
      end=(target['x'],target['y'])
      routes=aStar(map,(x,y),crd_game_to_gird(end),speed10)
      if routes:
        re_animal_1=target
        re_end_1=end
        re_routes_1=routes

        if target['type']==4 or target['type']==2 or canAdd(player['delivered'],target['type']):
          # 高分动物
          print('玩家所在行或列有动物')
          print('1.直接抓捕高分动物')
          return end,routes
        
        
  
  # 查找四个方向是否有能拦截的动物。注意只拦截4格就行。
  target=None
  distance=0
  re_animal_2=None
  re_end_2=None
  re_routes_2=None
  for dx,dy in dir.values():      
    x_,y_=x,y
    while True:
      x_,y_=x_+dx,y_+dy
      if x_>=0 and x_<map.shape[0] and y_ >=0 and y_<map.shape[1] and pass_map[x_][y_]==1:
        if one_map[x_][y_]!=0:
          distance_=abs(y_-y)+abs(x_-x)
          rowAnimalsPos=[crd_game_to_gird((x['x'],x['y'])) for x in animals if x['animalId'] in one_map[x_][y_]]
          distances=[abs(y_-pos[1])+abs(x_-pos[0]) for pos in rowAnimalsPos]
          maxDistance=max(distances)
          # 玩家前往拦截路径的时间需确保动物不会跑掉
          if (not target or distance_<distance) and distance_+maxDistance<=3 and maxDistance>=distance:
            target=(x_,y_)
            distance=distance_
            an_sort=sorted([x for x in animals if x['animalId'] in one_map[x_][y_]],key=lambda item:order[item['type']],reverse=True)
            if len(an_sort):
              re_animal_2=an_sort[0]
          break
      else:
        break
  

  if target:
    
    end=target
    routes=aStar(map,(x,y),target,speed10)
    if routes:
      re_end_2=crd_grid_to_game(end,50)
      re_routes_2=routes
      
      if re_animal_2['type']==4 or re_animal_2['type']==2 or canAdd(player['delivered'],re_animal_2['type']):
          # 高分动物
          return re_end_2,re_routes_2
        
  if re_animal_2:
    if re_animal_1 and order[re_animal_2['type']]<order[re_animal_1['type']]:
      return re_end_1,re_routes_1
    else:
      return re_end_2,re_routes_2
  elif re_animal_1:
    return re_end_1,re_routes_1

  # 尝试前往比较近的
  routesMap={}
  for animal in animals:
    routesMap[animal['animalId']]=aStar(map,(x,y),crd_game_to_gird((animal['x'],animal['y'])),speed10)
    if not routesMap[animal['animalId']]:
      routesMap[animal['animalId']]=[]
  animalsSorted=sorted(animals,key=lambda item:(order[item['type']],len(routesMap[item['animalId']])),reverse=True)
  target=None
  routes=[]
  for animal in animalsSorted:
    routes_=routesMap[animal['animalId']]
    if (not target) or (animal['type'] in [2,4]) or len(routes_)<len(routes):
      target=animal 
      routes=routes_
      if ((animal['type'] in [2,4]) or canAdd(player['delivered'],animal['type'])) and len(routes_)<=4:
        print('尝试直接前往比较近的')
        return (target['x'],target['y']),routes_
  
  if target and len(routes)<=6:
    return (target['x'],target['y']),routes
  
  # 周围没有动物,尽可能前往动物高密度区域
  animalMap2_3=np.zeros((2,3))
  for animal in animals:
    x,y=crd_2_3((animal['x'],animal['y']))
    animalMap2_3[x][y]+=1
  for p in stat['playerStateVos']:
    if p['playerId']!=stat['playerId']:
      x,y=crd_2_3((p['y'],p['x']))
      if animalMap2_3[x][y]>1:
        animalMap2_3[x][y]-=1
  
  arr=[]
  for i in range(0,animalMap2_3.shape[0]):
    for j in range(0,animalMap2_3.shape[1]):
      arr.append((animalMap2_3[i][j],(i,j)))
  arr=sorted(arr,key=lambda item:item[0],reverse=True)
  for animal in animals:
    x,y=crd_2_3((animal['x'],animal['y']))
    if (x,y)==arr[0][1]:
      routes=routesMap[animal['animalId']]
      print('前往高密度区域')
      return (animal['x'],animal['y']),routes
  
  
  


def canAdd(delivereds,type):
  "判断在抓一个type类型的动物是否能凑够一组"
  typeNum=0
  numMap={
  }
  for x in delivereds:
    if x == type:
      typeNum+=1
    else:
      if x not in numMap:
        numMap[x]=0
      numMap[x]+=1
  
  if len(numMap.values())==0:
    return False
  minType=min(numMap.values())

  return typeNum+1<=minType
  
  
  